Skip to content

Reintroduce system executable#1259

Merged
stevepolitodesign merged 29 commits into
mainfrom
sp-cli
Dec 19, 2025
Merged

Reintroduce system executable#1259
stevepolitodesign merged 29 commits into
mainfrom
sp-cli

Conversation

@stevepolitodesign
Copy link
Copy Markdown
Contributor

@stevepolitodesign stevepolitodesign commented Dec 11, 2025

Important

We're using this branch as a base for individual PRs, like #1260. In order to preserve commit history, do not Squash and merge.

Similar to the last rewrite, we generate a new gem and do a directory
swap, while making sure to preserve important files like NEWS.md.

This branch will serve as a new base for us to merge into while we build
up an application template.

This approach is largely inspired by Staples.

To do

Important

Before merging, make sure to run suspenders new <app_name> and complete the following:

QA

  • Running suspenders junk raises. It should return an error. @stevepolitodesign
  • main in app/views/layouts/application.html.erb contains class and aria-labelledby attributes, but should not.

Application Template

Existing Features

The following existing features need to be added to the application template.

For now, I recommend we ignore the following, since we can add them in later if needed:

  • Tasks since these would require Suspenders to be installed as part of the application. We can always do this later.
  • Linting since Rails ships with a linter, and some of our recommended tooling is out of date.
  • Stylesheets since for now, we don't want to prescribe anything. That being said, maybe we use Roux in a later release.

New Features

Documentation

  • Update generated README
    • Include prose about bin/dev
    • Include prose about bin/rails console --no-sandbox
  • Recommend caller should be using the latest version of Rails
  • Link to Suspenders and/or Playbook / Guides
  • Update FEATURES.md to account for things that were removed or modified. @stevepolitodesign
  • Update README.md to account for things that were removed or modified. @stevepolitodesign
  • Update README to highlight how to configure GitHub Actions @stevepolitodesign
    • Consider adjusting this
  • Update README to highlight how to deploy to Heroku @stevepolitodesign
    • Consider adjusting this

Clean up

  • Add YARD comments
  • Update NEWS.md and bump version
  • Support suspenders new and suspenders -v @laicuRoot
  • Print Ralph in the success message @laicuRoot

Nice to have

These can always be addressed in a follow-up release.

Comment thread .github/workflows/dynamic-readme.yml Outdated
Comment thread .github/workflows/dynamic-security.yml Outdated
Comment thread lib/suspenders/cli.rb
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@laicuRoot @purinkle this is the only thing Suspenders will do moving forward. It's just a wrapper for rails new.

Comment thread lib/templates/web.rb
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@laicuRoot @purinkle this is the file we can build up in separate PRs. You can refer to this template for guidance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving forward, you can test your changes locally by doing:

bundle exec rake install
suspenders <demo_app_name>

@stevepolitodesign stevepolitodesign force-pushed the sp-cli branch 5 times, most recently from 82e83d8 to adddd4f Compare December 11, 2025 12:17
Similar to the last rewrite, we generate a new gem and do a directory
swap, while making sure to preserve important files like NEWS.md.

This branch will serve as a new base for us to merge into while we build
up an [application template][template].

This approach is largely inspired by [staples][].

[template]: https://guides.rubyonrails.org/generators.html#application-templates
[staples]: https://github.com/stevepolitodesign/staples
Introduces [Procfile][1] to automatically start the server and run
migrations during the [release phase][2].

Additionally, we update our [database connection preference][3] to
account for [nuance in connecting with Heroku][4].

[1]:
https://devcenter.heroku.com/articles/getting-started-with-rails8#create-a-procfile
[2]: https://devcenter.heroku.com/articles/release-phase
[3]:
https://guides.rubyonrails.org/configuring.html#connection-preference
[4]:
https://discuss.rubyonrails.org/t/brainstorming-approaches-to-reconcile-rails-8s-default-multi-db-setup-with-database-url/86769
purinkle added a commit that referenced this pull request Dec 11, 2025
Before, the gem generated the default configuration for the test
environment. We wanted to raise errors when we missed a translation. We
enabled this configuration in the gem for the test environment.

[GitHub](#1259)

Co-authored-by: Jose Blanco <jose.blanco@thoughtbot.com>
Lifts from the existing [testing][], [factories][] and [ci][]
generators, while also relying on the fact that some of these files will
already exist. For example, `.github/workflows/ci.yml` will be generated
by Rails, we just need to modify the file.

The previous version of Suspenders could be invoked on an **existing**
application, but this new version is intended to be used when creating
**new** applications. Since we're calling `rails new` with `--skip-test`
we know that the `.github/workflows/ci.yml` will be missing the test
steps.

Also, this commit enables all the "recommended" settings in
`spec_helper`, which is a change from the current version.

This commit also updates the library's CI script to account for the fact
that the generated applicaiton uses RSpec.

[testing]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/ci_generator.rb
[factories]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/ci_generator.rb
[ci]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/ci_generator.rb
Lifted from the current [jobs generator][]. The only new addition is we
enable the web UI for local development, and configure for [Heroku][].

Since this commit adds a new process, we introduce `Procfile.dev`, and
update `bin/dev` based on [prior art][].

[jobs generator]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/jobs_generator.rb
[Heroku]: https://github.com/sidekiq/sidekiq/wiki/Heroku
[prior art]: https://github.com/rails/jsbundling-rails/blob/main/lib/install/dev
Lifted from existing [views generator][]. Note that we add a new
`app/views/application/_form_errors.html.erb` partial, and no longer
depend on the `title` gem, since Rails ships with a similar solution.

We also do not concern ourselves with any CSS framework (for now).

[views generator]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/views_generator.rb
Lifted from [email generator][]. However, we simplify the implementation
by removing the `include ActiveSupport::Configurable`. Instead, we just
create a simple PORO and place it in `lib`.

[email generator]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/email_generator.rb
Lifted from [development_generator][]. However, we do not need to enable
`annotate_rendered_view_with_filenames` or `query_log_tags_enabled`,
since those are now enabled by default. Also enables
`apply_rubocop_autocorrect_after_generate!` since this is a new option
since the last release.

[development_generator]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/environments/development_generator.rb
…1270)

Lifted from [production generator][]. Also adds the following new
settings:

- Enables [strict_loading_by_default][].
- Sets [strict_loading_mode][] to `:n_plus_one`.
- Enables [sandbox_by_default][].
- Sets [action_on_strict_loading_violation][] to `:log`.

This commit also introduces `ASSET_HOST` and `APPLICATION_HOST`
environment variables.

Finally, since we require the Rails Master Key, we update CI.

[production generator]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/environments/production_generator.rb
[strict_loading_by_default]:
https://guides.rubyonrails.org/configuring.html#config-active-record-strict-loading-by-default
[strict_loading_mode]:
https://guides.rubyonrails.org/configuring.html#config-active-record-strict-loading-mode
[sandbox_by_default]:
https://guides.rubyonrails.org/configuring.html#config-sandbox-by-default
[action_on_strict_loading_violation]:
https://guides.rubyonrails.org/configuring.html#config-active-record-action-on-strict-loading-violation
Prior to this commit, we were getting errors when running `bundle exec
rake install`.
@purinkle
Copy link
Copy Markdown
Contributor

@stevepolitodesign, out of curiosity, why are we burning everything to the ground and starting again? Is there a way to make this change incremental? It is a significant change for what is a public interface change. We are rewriting all the internals to accommodate the application template. Is there a way we could rearrange the code in main to accommodate the new approach? For example, extracting code from the generators so we can use it in both the generators and the template. It will allow us to merge code early and reduce the changes in this branch.

Furthermore, should we add new features at the same time we rewrite the functionality? Those could be two separate changes. We could introduce Strong Migrations into main and then add it to the template in this branch. All the above is to make this change more manageable and lightweight. I would love to know your thoughts.

Comment thread .github/workflows/main.yml Outdated
Comment thread .github/workflows/main.yml
Raplh now appears when an application is created successfully
Currently Suspenders does not include strong_migrations per default.
This is a thoughtbot recommendation in any new application.

In this PR, we introduce strong_migrations to be part of the defaults of
any new application created using suspenders.
@stevepolitodesign
Copy link
Copy Markdown
Contributor Author

stevepolitodesign commented Dec 12, 2025

Thank you for the feedback @purinkle!

@stevepolitodesign, out of curiosity, why are we burning everything to the ground and starting again?

Good question! The official guidance states:

Application templates are a little different from generators. While generators add files to an existing Rails application (models, views, etc.), templates are used to automate the setup of a new Rails application.

Suspenders is intended to create a new Rails application, and the official guidance is to use application templates. However, the existing code on main is a set of generators. This poses a few problems:

  • It goes against the official guidance.
  • It means we need to install suspenders into the new application just to generate code one-time. After that, there is no need to keep suspenders around.
  • The developer experience isn't great. We currently recommend running a cumbersome script, and it takes a long time to run, since each generator runs bundle install again.

Is there a way to make this change incremental?

The spirit of these changes is to first help us as an organization be consistent with how we generate new Rails applications. At the moment, we don't recommend Suspenders, and I'd love to change that ASAP.

Suspenders is a really unique open source project. Every time it changes, it's a major breaking change, since it fundamentally changes behavior. Even if we were to make an incremental change in an effort to keep the diff small, I don't think that would benefit us as consumers of the project.

It is a significant change for what is a public interface change.

I think that's OK though. I think it's a lot nicer to run suspenders new <app_name> compared to the following:

rails new app_name \
 --skip-rubocop \
 --skip-test \
 -d=postgresql \
 -m=https://raw.githubusercontent.com/thoughtbot/suspenders/main/lib/install/web.rb

Is there a way we could rearrange the code in main to accommodate the new approach? For example, extracting code from the generators so we can use it in both the generators and the template. It will allow us to merge code early and reduce the changes in this branch.

I recognize I'm biased because I have the most familiarity with the codebase, but I think burning everything to the ground and starting again is our best chance of making contributing and maintaining this application easier moving forward. It's also not the first time that we've done this 😈

This change drastically simplifies the codebase, since everything just lives in one template. I think this will help with maintenance and feature development, which has been a consistent problem.

Furthermore, should we add new features at the same time we rewrite the functionality? Those could be two separate changes. We could introduce Strong Migrations into main and then add it to the template in this branch. All the above is to make this change more manageable and lightweight. I would love to know your thoughts.

This is a good callout. Candidly, I figured since we're blowing everything away, this is a great opportunity to add in a few new "low risk" features. For example, our guides already recommend we set config.sandbox_by_default to true, I figured Suspenders should reflect that.

stevepolitodesign and others added 16 commits December 12, 2025 11:17
This was lifted from [Staples][], and I forgot to replace some of the
text.

[Staples]: https://github.com/stevepolitodesign/staples
Prior to this commit, we had no specs to test. This commit updates the
CI script by adding a basic static page, and adding a corresponding
system spec.

This revealed we had a broken layout, because we were including a
partial that does not exist.
Currently we do not support the options `-v` or `new` in Suspenders.

In this PR we introduce these two options and deprecating `suspenders
app_name`

Co-authored-by: Steve Polito <spolito@thoughtbot.com>
Makes documentation updates based on rewrite. A future commit could
explore reading from FEATURES.md when creating the generated README.md,
but for now, this works.
Adds notes on how to configure GitHub Actions and Heroku to play nice
with a generated application.
Fix syntax. Since this now actually uses Redis, we needed to update the CI script.
RSpec does not easily distinguish between system and non system tests,
so we just collapse these tasks into one.
Since we enable all the "recommended" RSpec features, we need to ignore
`/spec/examples.txt`, since that feature is enabled.
Alternative to #1261, lifted from the existing [generator][]. However,
since the authoring of that generator, the structure of
`config/environments/test.rb` has changed, so we no longer need
conditionals.

Additionally, we set `action_dispatch.show_exceptions` to `:none` rather
than comment it out to be explicit about the value.

[generator]: https://github.com/thoughtbot/suspenders/blob/main/lib/generators/suspenders/environments/test_generator.rb

Co-authored-by: Rob Whittaker <rob@thoughtbot.com>
Co-authored-by: Jose Blanco <53355525+laicuRoot@users.noreply.github.com>
Follow-up from #1273.

My recommended approach didn't account for calling an invalid command.

There's likely an opportunity to refactor this, but for now, it works.
Testing Suspenders is challenging because it's dependent on the current
version of Rails. Once there's a new release, things can break.

This commit aims to help make local development a little easier by
helping to distinguish code generated by `rails new` from code generated
by the application template.
The previous code was lifted from Staples. Although there wasn't
anything incorrect about it, we don't need a `class` or
`aria-labelledby` attributes. Those can be added as needed.
Add more details to the generated README, as well as the project README.
Introduce binstub to help automate the local QA experience.
…ks (#1288)

This closes #1251.

Since `db:seeds.rb` is intended to ensure

> ... the existence of records required to run the application in every
environment (production, development, test)

we have relied on [`dev:prime`][1] for loading data necessary for users
to view most of the features of the app in development.

However, there were a few areas of improvement.

First, rename `dev` namespace to `development`, and rename [`prime`][1]
task to `seed` for improved clarity.

Then, introduces `development:db:seed:replant` take to create parity
with the existing `db:seed:replant` task.

Introduces `Development::Seeder` class to encapsulate seed data, which
is called in the `development:db:seed` and `development:db:seed:replant`
tasks. The advantage to this is that the class can be called
independently from the task, and can also be [unit tested][2].

Finally, we ignore this class from being auto-loaded, since it's
intended for development use.

[1]: https://thoughtbot.com/blog/priming-the-pump
[2]: https://thoughtbot.com/blog/seeds-of-destruction
Add documentation, update release notes, bump version and run `bundle
exec rake build`.
@stevepolitodesign stevepolitodesign changed the title Re-introduce system executable Reintroduce system executable Dec 19, 2025
@stevepolitodesign stevepolitodesign merged commit 6e767d3 into main Dec 19, 2025
2 checks passed
@stevepolitodesign stevepolitodesign deleted the sp-cli branch December 19, 2025 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants